﻿using System;
using System.Collections.Generic;
using System.Text;
using DTO;
using DAO;
using System.Data;
using System.IO;
using System.Globalization;
using System.Xml;
using System.ComponentModel;
using System.Security.Cryptography;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;

namespace BUS
{
    public class BUSControl
    {
        #region Local variable
        public static string _docPath { get; set; }
        public static string _appPath { get; set; }
        Connection _conn = null;
        public string DB { get; set; }
        string ld = "A";
        public string LD { get { return ld; } set { ld = value; } }
        public string USER_ID { get; set; }
        public string PROCESSID { get; set; }
        public static bool DebugMode { get; set; }
        #endregion Local variable

        #region Transaction
        public Connection Connnection
        {
            get { return _conn; }
            set { _conn = value; }
        }
        public string GetDbType()
        {
            return _conn.DbType;
        }
        public object BeginTransaction(ref string sErr)
        {
            return _conn.BeginTransaction(ref sErr);
        }
        public object RollbackTransaction(ref string sErr)
        {
            return _conn.RollbackTransaction(ref sErr);
        }
        public object CommitTransaction(ref string sErr)
        {
            return _conn.CommitTransaction(ref sErr);
        }
        #endregion Transaction

        #region Initialize
        public BUSControl(BUSControl com)
        {
            _conn = com._conn;
            DB = com.DB;
            USER_ID = com.USER_ID;

        }

        public BUSControl(string type, string connectString, int timeout = 0)
        {
            _conn = new Connection(type, connectString, timeout);
        }

        public static void initDocumentPath()
        {
            if (!Directory.Exists(_docPath))
            {
                Directory.CreateDirectory(_docPath);
            }
            string logFolder = _docPath + "Log";
            if (!Directory.Exists(logFolder))
            {
                Directory.CreateDirectory(logFolder);
            }

            string tmpFolder = _docPath + "Templates";
            if (!Directory.Exists(tmpFolder))
            {
                Directory.CreateDirectory(tmpFolder);
            }

            string rptFolder = _docPath + "Reports";
            if (!Directory.Exists(rptFolder))
            {
                Directory.CreateDirectory(rptFolder);
            }
            //ValidateLicense(configureDirectory + "\\license.bin");
        }
        #endregion Initialize

        #region Execute Query
        public IDataReader executeQuery(string sqlString)
        {
            _conn.openConnection();
            IDataReader tmp = _conn.executeQuery(sqlString);
            _conn.closeConnection();
            return tmp;
        }

        public DataTable executeSelectQuery(string sqlString)
        {
            return _conn.executeSelectQuery(sqlString);
        }

        public void executeNonQuery(string sqlString)
        {
            _conn.openConnection();
            _conn.executeNonQuery(sqlString);
            _conn.closeConnection();
        }

        public object executeScalar(string sqlString)
        {
            _conn.openConnection();
            object tmp = _conn.executeScalar(sqlString);
            _conn.closeConnection();
            return tmp;
        }
        #endregion Execute Query

        #region Connection
        public bool TestConnection()
        {
            return _conn.TestConnect();
        }

        public string GetConnectionString()
        {
            return _conn.ConnectionString;
        }

        public static string getConnectString(string type, string server, string uid, string pwd, string dbname = "", int timeout = 0, int port = 1433)
        {
            return Connection.getConnectString(type, server, uid, pwd, dbname, timeout, port);
        }

        public void ChangeConnection(string type, string connectString, int timeout = 0)
        {
            _conn.ChangeConnection(type, connectString, timeout);
        }

        public void ChangeConnection(BUSControl bus)
        {
            _conn.ChangeConnection(bus.Connnection);
        }
        #endregion Connection

        #region Database Schema
        public DataTable GetDataBases(ref string sErr)
        {
            return _conn.GetDataBases(ref sErr);
        }

        public DataTable GetTables(string ptype, List<DTO.FilterParameter> filters, ref string sErr, int indexPage = 0, int itemPerPage = 0)
        {
            return _conn.GetTables(ptype, filters, ref sErr, indexPage, itemPerPage);
        }

        public DataTable GetFields(string table, ref string sErr)
        {
            return _conn.GetFields(table, ref sErr);
        }
        #endregion Database Schema

        #region Additional Method
        public static string ToRoman(int arabic)
        {
            string result = "";
            for (int i = 0; i < arabic; i++)
            {
                while (arabic >= 1000)
                {//check for thousands place

                    result = result + "M";
                    arabic = arabic - 1000;
                }
                while (arabic >= 900)
                {
                    //check for nine hundred place
                    result = result + "CM";
                    arabic = arabic - 900;
                }
                while (arabic >= 500)
                {
                    //check for five hundred place
                    result = result + "D";
                    arabic = arabic - 500;
                }
                while (arabic >= 400)
                {
                    //check for four hundred place
                    result = result + "CD";
                    arabic = arabic - 400;
                }
                while (arabic >= 100)
                {
                    //check for one hundred place
                    result = result + "C";
                    arabic = arabic - 100;
                }
                while (arabic >= 90)
                {
                    //check for ninety place
                    result = result + "XC";
                    arabic = arabic - 90;
                }
                while (arabic >= 50)
                {
                    //check for fifty place
                    result = result + "L";
                    arabic = arabic - 50;
                }
                while (arabic >= 40)
                {
                    // check for forty place
                    result = result + "XL";
                    arabic = arabic - 40;
                }

                while (arabic >= 10)
                {
                    // check for tenth place
                    result = result + "X";
                    arabic = arabic - 10;
                }
                while (arabic >= 9)
                {
                    //check for nineth place
                    result = result + "IX";
                    arabic = arabic - 9;
                }
                while (arabic >= 5)
                {
                    //check for fifth place
                    result = result + "V";
                    arabic = arabic - 5;
                }
                while (arabic >= 4)
                {
                    //check for fourth place
                    result = result + "IV";
                    arabic = arabic - 4;
                }
                while (arabic >= 1)
                {
                    //check for first place
                    result = result + "I";
                    arabic = arabic - 1;
                }
            }
            return result;
        }


        public static void AddLog(string type, string message)
        {
            AddLog(type, "SYS", "SYS", message, "");
        }
        public static void AddLog(string type, string target, string message)
        {
            AddLog(type, "SYS", target, message, "");
        }

        public static void AddLog(string type, string uid, string target, string message, string processID)
        {
            GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
            int week = cal.GetWeekOfYear(DateTime.Today, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
            string erroFile = _docPath + "local_logs\\" + type + DateTime.Today.Year.ToString("0000") + week.ToString("000") + ".log";
            //System.IO.StreamWriter sw = new System.IO.StreamWriter(erroFile);
            if (!File.Exists(erroFile))
            {
                using (StreamWriter sw = File.CreateText(erroFile))
                {
                    sw.WriteLine(string.Format("[{0:yyyy-MM-dd HH:mm:ss}] {1} ({2}) {3}: {4}", DateTime.Now, uid, processID, target, message).Replace(Environment.NewLine, " "));
                }

            }
            else
            {
                using (FileStream file = new FileStream(erroFile, FileMode.Append))
                {
                    using (StreamWriter sw = new StreamWriter(file))
                    {
                        sw.WriteLine(string.Format("[{0:yyyy-MM-dd HH:mm:ss}] {1} ({2}) {3}: {4}", DateTime.Now, uid, processID, target, message).Replace(Environment.NewLine, " "));
                    }
                }
            }
        }

        public static string RemoveAttribute(String input, string attribute)
        {
            int indexS = input.IndexOf(attribute, 0);
            if (indexS != -1)
            {
                int indexE = input.IndexOf(";", indexS + attribute.Length);
                if (indexE == -1 || indexE == input.Length - 1)
                    return input.Substring(0, indexS);
                return input.Substring(0, indexS) + input.Substring(indexE + 1);
            }
            else
                return input;
        }

        public static string HiddenAttribute(String input, string attribute)
        {
            int indexS = input.IndexOf(attribute, 0);
            if (indexS != -1)
            {
                int indexE = input.IndexOf(";", indexS + attribute.Length);
                if (indexE == -1 || indexE == input.Length - 1)
                    return attribute + "=******;" + input.Substring(0, indexS);
                return input.Substring(0, indexS) + attribute + "=*****;" + input.Substring(indexE + 1);
            }
            else
                return attribute + "=*****;" + input;
        }

        public static string GetParseExpressionDate(string columnDate, string type)
        {
            string result = "SUBSTRING(CONVERT(" + columnDate + ",System.String),7,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),5,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),1,4)";
            switch (type)
            {
                case "A":
                    result = "SUBSTRING(CONVERT(" + columnDate + ",System.String),5,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),7,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),1,4)";
                    break;
                case "B":
                    result = "SUBSTRING(CONVERT(" + columnDate + ",System.String),7,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),5,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),1,4)";
                    break;
                case "C":
                    result = "SUBSTRING(CONVERT(" + columnDate + ",System.String),1,4)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),5,2)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),7,2)";
                    break;
            }
            return result;
        }

        public static string GetParseExpressionPeriod(string columnDate)
        {
            string result = "IIF(" + columnDate + ">1900001,SUBSTRING(CONVERT(" + columnDate + ",System.String),5,3)+'/'+SUBSTRING(CONVERT(" + columnDate + ",System.String),1,4),0)";
            return result;
        }

        public static byte[] GetHash(string inputString)
        {
            HashAlgorithm algorithm = SHA1.Create();  // MD5.Create()
            return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
        }

        public static string GetHashString(string inputString)
        {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            foreach (byte b in GetHash(inputString))
            {
                i++;
                sb.Append(b.ToString("X2"));
                if (i % 2 == 0) sb.Append("-");
            }


            return sb.ToString().Substring(0, sb.Length - 1);
        }
        public static string getUniqueNumber(int len = 15)
        {
            string t = Guid.NewGuid().ToString("N").ToUpper();
            len = Math.Min(len, t.Length);
            return t.Substring(0, len);
            // return DateTime.UtcNow.ToFileTimeUtc().ToString();
        }
        public static string getDB(string accountName)
        {
            int idx = accountName.IndexOf("@");
            if (idx == -1)
                return accountName;
            return accountName.Substring(idx, accountName.Length - idx);

        }

        public static byte[] GetBytes(string str)
        {
            if (str == "" || str == null) return null;

            byte[] bytes = new byte[str.Length * sizeof(char)];
            System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }

        public static string GetString(byte[] bytes)
        {
            if (bytes == null) return null;

            char[] chars = new char[bytes.Length / sizeof(char)];
            System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
            return new string(chars);
        }
        #endregion Additional Method

        #region DTO Method
        public virtual DataTable Preview2DataTable(XmlDocument xml, ref string logMsg, string db = null)
        {
            XmlElement doc = xml.DocumentElement;
            DataTable dt = new DataTable(doc.Name);

            try
            {
                foreach (XmlElement ele in doc.ChildNodes)
                {
                    DataRow r = dt.NewRow();
                    foreach (XmlAttribute att in ele.Attributes)
                    {
                        if (!dt.Columns.Contains(att.Name)) dt.Columns.Add(att.Name);
                        r[att.Name] = att.InnerText;
                    }
                    dt.Rows.Add(r);
                }
            }
            catch (Exception ex)
            {
                logMsg = ex.Message;
            }
            return dt;
        }

        public virtual DTOInfo[] Preview(XmlDocument xml, ref string sErr, string db = null) { return null; }
        public virtual string TransferIn(DTOInfo inf, TransferMode mode) { return ""; }
        public virtual string TransferIn(DataRow inf, TransferMode mode) { return ""; }
        public virtual string TransferIn(DataRowView inf, TransferMode mode) { return TransferIn(inf.Row, mode); }

        public virtual string ToXmlString(DTOInfo[] lInf, ref string sErr) { return ""; }
        public string ToXmlString(DataTable dt, ref string sErr)
        {
            string result = "";
            try
            {
                XmlDocument xml = new XmlDocument();
                XmlElement doc = xml.CreateElement(dt.TableName);
                xml.AppendChild(doc);
                foreach (DataRow r in dt.Rows)
                {
                    XmlElement row = xml.CreateElement("row");
                    foreach (DataColumn c in dt.Columns)
                    {
                        if (c.DataType == typeof(DateTime))
                            row.SetAttribute(c.ColumnName, string.Format("{0:yyyy-MM-dd}", r[c]));
                        else row.SetAttribute(c.ColumnName, string.Format("{0}", r[c]));
                    }
                    doc.AppendChild(row);
                }

                using (MemoryStream ms = new MemoryStream())
                {
                    xml.Save(ms);
                    using (StreamReader sr = new StreamReader(ms))
                    {
                        result = sr.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                sErr = ex.Message;

            };
            return result;
        }

        public enum TransferMode
        {
            AddNew,
            Update,
            All
        }

        protected string GetStringAttribute(XmlElement ele, string p)
        {
            return ele.GetAttribute(p);
        }

        protected DateTime? GetDateTimeAttribute(XmlElement ele, string p)
        {
            DateTime? res = null;
            string date = ele.GetAttribute(p);
            if (date == "") return null;

            try { res = DateTime.Parse(date); }
            catch { }
            return res;
        }

        protected int? GetInt32Attribute(XmlElement ele, string p)
        {
            int? res = null;
            string date = ele.GetAttribute(p);
            if (date == "") return null;

            try { res = int.Parse(date); }
            catch { }
            return res;
        }

        protected long? GetInt64Attribute(XmlElement ele, string p)
        {
            long? res = null;
            string date = ele.GetAttribute(p);
            if (date == "") return null;

            try { res = long.Parse(date); }
            catch { }
            return res;
        }

        protected short? GetInt16Attribute(XmlElement ele, string p)
        {
            short? res = null;
            string date = ele.GetAttribute(p);
            if (date == "") return null;

            try { res = short.Parse(date); }
            catch { }
            return res;
        }
        protected decimal? GetDecimalAttribute(XmlElement ele, string p)
        {
            decimal? res = null;
            string date = ele.GetAttribute(p);
            if (date == "") return null;

            try { res = decimal.Parse(date); }
            catch { }
            return res;
        }

        protected double? GetDoubleAttribute(XmlElement ele, string p)
        {
            double? res = null;
            string date = ele.GetAttribute(p);
            if (date == "") return null;

            try { res = double.Parse(date); }
            catch { }
            return res;
        }

        public virtual string GetDefaultValue(string val)
        {
            DateTime today = DateTime.Today;
            if (val == "T") return today.ToString("yyyy-MM-dd");
            else if (val == "FM") return string.Format("{0:yyyy-MM}-{1:00}", today, 1);
            else if (val == "EM") return string.Format("{0:yyyy-MM}-{1:00}", today, DateTime.DaysInMonth(today.Year, today.Month));
            else if (val == "FY") return string.Format("{0:yyyy}-{1:00}-{2:00}", today, 1, 1);
            else if (val == "EY") return string.Format("{0:yyyy}-{1:00}-{2:00}", today, 12, 31);
            else if (val == "C") return "";
            else if (val == "S") return "";
            else if (val == "E") return "";
            return val;
        }

        #endregion


        public string GetMinSqlServerVersion()
        {
            return _conn.GetMinSqlServerVersion();
        }

        public virtual bool isField(string field)
        {
            return true;
        }

        public string GetSqlServerVersion()
        {
            return _conn.GetSqlServerVersion();
        }

        public int GetTableCount(string table, List<FilterParameter> filters, ref string logMsg)
        {
            return _conn.GetTableCount(table, filters, ref  logMsg);
        }

        public static string GetMACAddress()
        {
            string DanhSachMAC = "";
            System.Net.NetworkInformation.NetworkInterface[] DanhSachCardMang = NetworkInterface.GetAllNetworkInterfaces();
            for (int i = 0; i < DanhSachCardMang.Length; i++)
            {
                PhysicalAddress DiaChiMAC = DanhSachCardMang[i].GetPhysicalAddress();
                DanhSachMAC += DanhSachCardMang[i].Name + " : ";
                byte[] ByteDiaChi = DiaChiMAC.GetAddressBytes();
                for (int j = 0; j < ByteDiaChi.Length; j++)
                {
                    DanhSachMAC += ByteDiaChi[j].ToString("X2");
                    if (j != ByteDiaChi.Length - 1)
                    {
                        DanhSachMAC += "-";
                    }
                }
                DanhSachMAC += " ";
                //  txtMAC.Text += DanhSachMAC;
            }
            return DanhSachMAC;
        }

        public class Drive
        {
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool GetVolumeInformation(
                string rootPathName,
                StringBuilder volumeNameBuffer,
                int volumeNameSize,
                ref uint volumeSerialNumber,
                ref uint maximumComponentLength,
                ref uint fileSystemFlags,
                StringBuilder fileSystemNameBuffer,
                int nFileSystemNameSize);

            public string VolumeName { get; private set; }

            public string FileSystemName { get; private set; }

            public uint SerialNumber { get; private set; }

            public string DriveLetter { get; private set; }

            public static Drive GetDrive(string driveLetter)
            {
                const int VolumeNameSize = 255;
                const int FileSystemNameBufferSize = 255;
                StringBuilder volumeNameBuffer = new StringBuilder(VolumeNameSize);
                uint volumeSerialNumber = 0;
                uint maximumComponentLength = 0;
                uint fileSystemFeatures = 0;
                StringBuilder fileSystemNameBuffer = new StringBuilder(FileSystemNameBufferSize);

                if (GetVolumeInformation(
                    string.Format("{0}:\\", driveLetter),
                    volumeNameBuffer,
                    VolumeNameSize,
                    ref volumeSerialNumber,
                    ref maximumComponentLength,
                    ref fileSystemFeatures,
                    fileSystemNameBuffer,
                    FileSystemNameBufferSize))
                {
                    return new Drive
                    {
                        DriveLetter = driveLetter,
                        FileSystemName = fileSystemNameBuffer.ToString(),
                        VolumeName = volumeNameBuffer.ToString(),
                        SerialNumber = volumeSerialNumber
                    };
                }

                // Something failed, returns null
                return null;
            }
        }

        public static string GetHDPhysicalId()
        {
            string id = "";
            Drive drive = Drive.GetDrive("C");

            id += string.Format("Volumne name: {0} ", drive.VolumeName);
            id += string.Format("File system name: {0} ", drive.FileSystemName);
            id += string.Format("SerialNumber: {0:X} ", drive.SerialNumber);
            return id;
        }
    }
}
